MÓNADAS

La generalización de las continuaciones

“La mónada no es sino una sustancia simple que entra en entidades compuestas; simple, es decir, sin partes” (Leibniz. Monadología)



Mónada en teoría de categorías

El concepto de mónada (en inglés, monad) pertenece a la teoría de categorías.

Una categoría está formada por una clase (un conjunto de objetos) y un conjunto de morfismos. Un morfismo (o flecha) es una relación dirigida entre dos objetos A y B de la clase (una relación binaria), que se expresa como AB.

Una categoría C cumple los dos axiomas siguientes:
  1. Composición asociativa de morfismos:
    h ο (g ο f) = (h ο g) ο f

  2. Morfismo identidad. Para todo objeto x de C existe un morfismo identidad 1x que le hace corresponder a sí mismo.
Un funtor (o functor) es una función de una categoría a otra que lleva objetos a objetos y morfismos a morfismos de manera que la composición de morfismos y las identidades se preservan. Un endofunctor es un funtor de una categoría sobre sí misma.

Una transformación natural transforma un funtor en otro respetando su estructura interna, es decir la composición de morfismos, de las categorías implicadas. Se puede considerar como un morfismo de funtores.

Una vez revisados estos conceptos de la teoría de categorías, podemos dar la definición formal de mónada sobre una categoría C, también llamada “triple” porque se define mediante tres axiomas: Podemos considerar una mónada como una categoría en la que los objetos son estados de un sistema y los morfismos son funciones de transición entre estados.


Mónadas en lenguajes de programación funcionales

Como el concepto clave de la teoría de categorías es el de morfismo, las mónadas se están aplicando en los lenguajes de programación funcionales. Estos lenguajes son de dos tipos: La tendencia es integrar ambos aspectos en los lenguajes funcionales. Uno de los mecanismos utilizados para este fin es precisamente el uso de mónadas. Las mónadas se utilizan como mecanismo complementario de los lenguajes funcionales puros para que soporten el paradigma imperativo. En programación funcional, una mónada es una estructura que representa una secuencia de transformaciones de un objeto. Para usar las mónadas en un lenguaje funcional no es necesario tener un conocimiento previo de la teoría de categorías.

La idea básica de una mónada en programación funcional es la siguiente: La función mónada también se denomina “contenedor”, pues contiene a la función original.


Mónadas en Haskell

Haskell [Bird, 2000], uno de los lenguajes funcionales puros más conocidos, utiliza mónadas. En Haskell las tres funciones de las mónadas se reducen a dos: return y bind (ligar, unir). Esta última se representa como “>>=”.

En Haskell, por definición, M es una mónada cuando posee las dos operaciones siguientes:
  1. return :: aM a
    Esta operación admite varias interpretaciones:


    Por ejemplo, en la interpretación del contenedor, si tengo una manzana (a), la puedo poner en una caja (M).

  2. (>>=) :: M a → (aM b) → M b
    Combina dos computaciones en secuencia, pasando el resultado de la primera como argumento de la segunda. Esta operación es asociativa.

    Se aplica la función (aM b) con el valor de entrada (M a), cuyo resultado es M(M b)) que se junta para obtener un contenedor de tipo (M b).

    Por ejemplo, si tengo una caja de manzanas (M a), y si por cada manzanza obtengo una caja de peras, entonces puedo obtener una caja con todas las peras juntas.
Haskell también define la meta-función fmap, que aplica una función f a todos los elementos de un contenedor, de tal manera que los objetos a, b, c, … del contenedor se transforman en f(a), f(b), f(c), … y los morfismos de tipo ab se transforman en f(a) → f(b). Se define así: Por ejemplo, si de cada manzana obtengo una pera (ab), de una caja de manzanas obtengo una caja de peras (fafb).

La función fmap es un caso particular del denominado “lifting monádico”, donde se sustituyen valores básicos por valores monádicos, es decir, generaliza una función sustituyendo los argumentos por contenedores. En general,

f(T1Tn) → rf(MT1MTn) → Mr

Las mónadas transformaron Haskell convirtiéndolo en un lenguaje de programación imperativo. Haskell popularizó el uso de mónadas para la programación imperativa con la notación do.


Mónadas vs. Continuaciones

Una continuación se puede expresar así: f(x, c) = c(f(x)), es decir, la continuación c es una función que es un parámetro de otra función. Por ejemplo, Existe una estrecha relación entre mónadas y continuaciones. En ambos casos hay que especificar una función adicional: Si se utilizan mónadas, la especificación de continuaciones se hace más simple, más claro y más fácil de actualizar, pues no hay que modificar todo el programa, solo hay que redefinir las mónadas.

Eugenio Moggi [1989] ha demostrado que el concepto de mónada es más general que el de continuación. Dicho de otra forma, una continuación es un caso particular de mónada. La composición de continuaciones tiene estructura monádica.


Mónadas, álgebra abstracta y álgebra universal

Una mónada es esencialmente un monoide en una categoría endofuntora. En álgebra abstracta, un monoide es una estructura algebraica con una operación binaria interna, que es asociativa y que tiene un elemento neutro. Es decir, una mónada es un semigrupo con elemento neutro. Un semigrupo es un conjunto con una operación interna asociativa.

El álgebra universal es una generalización del álgebra abstracta que estudia las propiedades comunes y genéricas de todas las operaciones y estructuras algebraicas sobre un conjunto. Es una especie de meta-teoría algebraica basada en un pequeño número de axiomas.

La teoría de categorías y el álgebra universal tienen como objetivo la fundamentación de todas las estructuras algebraicas. El álgebra universal se basa en las operaciones internas que definen la estructura. La teoría de categorías se basa en morfismos.

El álgebra universal se puede formular en términos de la teoría de categorías, en particular se puede definir en términos de mónadas. Por lo tanto, con las mónadas se puede construir toda estructura algebraica. Existe una equivalencia entre el álgebra universal y las mónadas en la categoría Sets (la categoría de los conjuntos). Las mónadas permiten expresar de forma compacta ciertos aspectos del álgebra universal.

Las mónadas suministran una visión diferente del álgebra universal. Por ejemplo, las variedades se pueden representar con mónadas. El álgebra universal es esencialmente el estudio de las variedades. Una variedad es una generalización de curva (1-variedad) y superficie (2-variedad) a n dimensiones.


Ventajas y limitaciones de las mónadas en los lenguajes funcionales puros

Las ventajas son: Y las limitaciones son importantes:
Implementación de Mónadas en MENTAL

Teoría de categorías vs. MENTAL

La teoría de categorías es una teoría con un fundamento simple (relaciones binarias entre objetos). Pero paradójicamente es una teoría compleja, antinatural, demasiado abstracta y poco intuitiva por dos razones: 1) por fundamentarse en una sola primitiva conceptual (el morfismo); 2) porque esta primitiva es ambigua, no tiene semántica definida, es abierta, pues el concepto de morfismo admite muchas interpretaciones.

Además, la teoría de categorías es poco adecuada para fundamentar la matemática y poco adecuada para aplicarla a la programación. Las verdaderas categorías son las primitivas semánticas universales, que establecen los grados de libertad. [ver Aplicaciones – Matemática – Teoría de Categorías].


Mónadas vs. expresiones genéricas

El concepto de mónada es tan confuso que se ha intentado definir de muchas formas, entre ellas las siguientes: Incluso se ha afirmado que el concepto de mónada es inefable, que no es posible definirlo y que solo podemos usarlo en aplicaciones concretas.

La definición que parece que quizás más se aproxima al concepto es la siguiente: una mónada es un patrón de diseño para componer funciones con tipos extendidos. Un tipo extendido es un tipo más general que incluye al tipo básico.

Sin embargo, esta definición no es suficientemente clara. Las mónadas son realmente expresiones genéricas disfrazadas. Con las expresiones genéricas de MENTAL los mecanismos de las mónadas se simplifican y aclaran. Además, se superan sus limitaciones.
Ejemplos

En el tema de la relación entre objetos y tranformaciones, existen dos procesos extremos:
  1. Una misma función se aplica sucesivamente a varios objetos de una secuencia. Corresponde a la meta-función fmap de algunos lenguajes de programación funcional como Haskell y Lisp. Se trata de una función de orden superior que aplica la función inicial a cada elemento de una lista, retornando una lista de resultados en el mismo orden.

  2. Un mismo objeto es sometido a varias transformaciones sucesivas.
En la práctica, estos dos tipos de procesos pueden llegar a confundirse, pues una secuencia de objetos se puede considerar un solo objeto.

Estos dos procesos se pueden especificar de una manera extremadamente simple en MENTAL.

En el primer caso, la meta-función fmap se expresa así:

⟨( (fmap f x) = ( [f([x↓])] ) )⟩
(f se aplica a cada uno de los componentes de x)

Ejemplos:
  1. ⟨( f(x) = x*x )⟩)
    (a = (1 2 3 4))
    (fmap f a) // ev. (1 4 9 16)


  2. ⟨( f(x) = (x x+10)↓ )⟩
    (a = (1 2 3 4))
    (fmap f a) // ev. (1 11 2 12 3 13 4 14)


  3. Queremos someter una secuencia numérica a una transformación tal que cada elemento de la secuencia se transforme en dos secuencias:


    Por ejemplo, si tenemos el objeto (1, 2, 3, 4), el resultado es


    En MENTAL:


    Esta función convierte un número en una expresión abierta formada por dos secuencias.

En el segundo caso tenemos, por ejemplo, las funciones: En este ejemplo, las funciones se pueden encadenar sin problemas. Pero hay veces que el encadenamiento no puede realizarse de forma mecánica cuando hay errores, por ejemplo, al tratar de calcular la raíz cuadrada de un número negativo. Por ejemplo:

Definimos ⟨( fοg = g(f) )⟩ (composición de funciones)
con la propiedad asociativa:
⟨( (fοg)οh ≡ fο(gοh) )⟩.

Por ejemplo,
(sqrt(r) ο sumar5(r))
se evalúa como (sumar5(sqrt(r))),
siendo ⟨( sumar5(r) = r+5 )⟩.

Suponemos que la función sqrt(r) devuelve la raíz cuadrada de r si es r>0 o el texto “error” si r<0. La función siguiente debe chequear primero, antes de aplicarla, que el resultado de la función anterior es un número y no un mensaje de error. Si detecta el mensaje de error, su respuesta debe ser también el mismo mensaje de error. La nueva función sería: Este mismo mecanismo habría que aplicarlo a las posibles siguientes funciones de la cadena. Para no repetirlo, podemos crear una expresión genérica: Por lo tanto, la expresión de concatenación de las dos funciones sería: En este ejemplo se podrían especificar dos valores de salida (el resultado de la función y un mensaje que indique si ha habido error o no.



Adenda

Orígen de las mónadas

El término “mónada” está prestado de Leibniz, de la misma forma que el término “categoría” está prestado de Kant. Para Leibniz, una mónada es una sustancia simple que forma parte de todos los elementos de la realidad.

Saunders Mac Lane cofundador de la teoría de categorías, junto con Samuel Eilenberg adoptó el término filosófico de “mónada” para hacer referencia a algo general, una entidad capaz de generar todas las otras entidades. Pero eso no significa que la mónada sea simple, pues el concepto de mónada en teoría de categorías es muy abstracto, complejo y poco intuitivo, por lo que va en contra de la concepción de Leibniz. La popularidad del término ¨mónada” se debe probablemente al propio Mac Lane por su influyente libro Category Theory for the Working Mathematician. También se cree que el término “mónada” fue motivada y estimulada por su similitud con la palabra “monoide”, pues una mónada es un monoide.

Las mónadas han sido conocidas por otros nombres: triple o triada (por su definición mediante tres axiomas) y construcción estándar (por su pretensión de ser algo que fundamentase todo lo demás). La primera mónada que se construyó fue presentada por Roger Godemont en 1958 [Barr & Wells, 1985].

Eugenio Moggi [1989, 1990, 2000] fue el primero en introducir las mónadas en computación, concretamente en el área de la semántica denotacional [Stoy, 1997] para intentar modelar su significado. La semántica denotacional se basa en asignar a cada elemento del lenguaje un objeto matemático.

Spivey [1990] descubrió que las mónadas proporcionaban una forma fácil de de tratar las excepciones.

Philip Wadler [1990, 1992, 1995, 1997] popularizó las ideas de Moggi al proponer las mónadas como una técnica general para extender los lenguajes funcionales a la programación imperativa.

Las mónadas se han utilizado en el desarrollo del compilador de Haskell de Glasgow (que está escrito en Haskell).


Aplicaciones de las mónadas

Las mónadas se están aplicando, en diversos campos:
Mónadas predefinidas en Haskell

Haskell suministra mónadas predefinidas para utilizarlas como funciones y para combinación de funciones.

MónadaDescripción
MaybeComputaciones que pueden retornar o no un resultado
IdentityMónada identidad
[] (List)Computaciones que retornan múltiples resultados
IOComputaciones que realizan Entrada/Salida
ErrorComputaciones que pueden fallar o producir excepciones
StateComputaciones que mantienen el estado
ReaderComputaciones que leen datos
WriterComputaciones que escriben datos
ContComputaciones que pueden interrumpirse o reiniciarse


Bibliografía